package com.meilai.project.util;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.*;
import com.meilai.project.exception.CommonException;
import com.meilai.project.util.interf.OssUtilInterface;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;

@Component
@Log4j2
public class OssAliyunUtil implements OssUtilInterface {
    @Value("${aliyun.oss.endpoint}")
    private String endpoint;
    @Value("${aliyun.oss.innerEndpoint}")
    private String innerEndpoint;
    @Value("${aliyun.oss.accessKeyId}")
    private String accessKeyId;
    @Value("${aliyun.oss.accessKeySecret}")
    private String accessKeySecret;
    @Value("${aliyun.oss.bucketName}")
    private String bucketName;
    @Value("${aliyun.oss.url}")
    private String url;

    /**
     * 获取阿里云OSS客户端对象
     *
     * @return ossClient
     */
    private OSSClient getOSSClient() {
        return new OSSClient(endpoint, accessKeyId, accessKeySecret);
    }

    private OSS getInnerOSSClient(){
        return new OSSClientBuilder().build(innerEndpoint, accessKeyId, accessKeySecret);
    }

    /**
     * ecs下载oss文件
     * @param file_name attachments表的file_name字段
     * @param path 本地文件路径，存在会覆盖，不存在则新建
     */
    public void innerDownloadFile(String file_name, String path){
        OSS ossClient = getInnerOSSClient();
        // 下载Object到本地文件
        ObjectMetadata meta = ossClient.getObject(new GetObjectRequest(bucketName, file_name), new File(path));
        // 关闭OSSClient。
        ossClient.shutdown();
    }

    /**
     * ecs下载oss文件流字节数组
     * @param file_name attachments表的file_name字段
     */
    public byte[] innerDownloadByte(String file_name) {
        log.info("进入innerDownloadByte方法："+file_name);

        byte[] bytes = new byte[0];
        OSS ossClient = getInnerOSSClient();
        // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
//        OSSObject ossObject = ossClient.getObject(bucketName, file_name);
        //处理图片格式，宽为300px
//        String style = "image/resize,w_300";
        GetObjectRequest request = new GetObjectRequest(bucketName, file_name);
//        request.setProcess(style);
        OSSObject ossObject = ossClient.getObject(request);

        StringBuilder str = new StringBuilder("");
        try{
            log.info("进入innerDownloadByte方法进度2："+file_name);
            // 读取文件内容。
            InputStream input = ossObject.getObjectContent();
            ByteArrayOutputStream output = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024*4];
            int n = 0;
            while (-1 != (n = input.read(buffer))) {
                output.write(buffer, 0, n);
            }
            bytes = output.toByteArray();
        }catch (IOException e){
            log.error("内网下载oss文件，转换字节失败！");
        }
        // 关闭OSSClient。
        ossClient.shutdown();
        return bytes;
    }
    public byte[] innerDownloadByte2(String file_name,String setting) {
        log.info("进入innerDownloadByte方法："+file_name);

        byte[] bytes = new byte[0];
        OSS ossClient = getInnerOSSClient();
        // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
//        OSSObject ossObject = ossClient.getObject(bucketName, file_name);
        //处理图片格式，宽为300px
        String style = setting;
        GetObjectRequest request = new GetObjectRequest(bucketName, file_name);
        request.setProcess(style);
        OSSObject ossObject = ossClient.getObject(request);

        StringBuilder str = new StringBuilder("");
        try{
            log.info("进入innerDownloadByte方法进度2："+file_name);
            // 读取文件内容。
            InputStream input = ossObject.getObjectContent();
            ByteArrayOutputStream output = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024*4];
            int n = 0;
            while (-1 != (n = input.read(buffer))) {
                output.write(buffer, 0, n);
            }
            bytes = output.toByteArray();
        }catch (IOException e){
            log.error("内网下载oss文件，转换字节失败！");
        }
        // 关闭OSSClient。
        ossClient.shutdown();
        return bytes;
    }
    private String getBaseUrl() {
        return "https://" + url + "/";
    }

    /**
     * 阿里云OSS对象存储简单上传实现
     */
    @Override
    public void store(InputStream inputStream, long contentLength, String contentType, String keyName) {
        try {
            // 简单文件上传, 最大支持 5 GB, 适用于小文件上传, 建议 20M以下的文件使用该接口
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentLength(contentLength);
            objectMetadata.setContentType(contentType);
            // 对象键（Key）是对象在存储桶中的唯一标识。
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, keyName, inputStream, objectMetadata);
            PutObjectResult putObjectResult = getOSSClient().putObject(putObjectRequest);
        } catch (Exception ex) {
            throw new CommonException(ex.getMessage());
        }

    }

    @Override
    public void storeSimple(InputStream inputStream, String keyName) {
        try {
            // 简单文件上传, 最大支持 5 GB, 适用于小文件上传, 建议 20M以下的文件使用该接口
            OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
            ossClient.putObject(bucketName, keyName, inputStream);
            ossClient.shutdown();
        } catch (Exception ex) {
            throw new CommonException(ex.getMessage());
        }
    }

    public Resource loadAsResource(String keyName) {
        try {
            URL url = new URL(getBaseUrl() + keyName);
            Resource resource = new UrlResource(url);
            if (resource.exists() || resource.isReadable()) {
                return resource;
            } else {
                return null;
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public void delete(String keyName) {
        try {
            getOSSClient().deleteObject(bucketName, keyName);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @Override
    public String generateUrl(String keyName) {
        return getBaseUrl() + keyName;
    }

    /**
     * 上传私密文件至私有bucket
     * 上传至私有bucket的时候 返回key 每次通过key读取文件链接
     * 链接有效时间两小时
     * Date expiration = new Date(new Date().getTime() + 3600l * 1000 * 2);
     *
     * @param inputStream 上传文件
     * @param keyName
     * @param session
     * @param request
     * @return
     * @throws Exception
     */
    public void storeToll(InputStream inputStream, String keyName, long contentLength, String contentType, HttpSession session, HttpServletRequest request) throws Exception {
        // 创建OSSClient实例
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        try {
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentLength(contentLength);
            objectMetadata.setContentType(contentType);
            // 上传 --> 带进度条上传
            ossClient.putObject(new PutObjectRequest(bucketName, keyName, inputStream, objectMetadata).withProgressListener(new PutObjectProgressListener(session)));
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 关闭client
        ossClient.shutdown();
    }
}
